/*
 * Copyright 2010
 * This file is part of XXXXXX.
 * XXXXXX is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * XXXXXX is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * XXXXXX; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
 * Fifth Floor, Boston, MA 02110-1301 USA
 */
package PD.modules.simulation.Body;

import PD.data.NetworkDataset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

/**
 *
 * @author bicha
 */
public class Body {

        NetworkDataset subNetwork;
        List<Chromosome> genome;
        Random rand;
        int maxNumChromosomes;
        double maxWeight;

        public Body(NetworkDataset dataset, int maxNumberChromosomes) {
                this.subNetwork = dataset;
                this.genome = new ArrayList<Chromosome>();
                this.maxNumChromosomes = maxNumberChromosomes;
                this.rand = new Random();
                if (this.subNetwork != null) {
                        for (int i = 0; i < maxNumberChromosomes; i++) {
                                Chromosome chromosome = new Chromosome(dataset.clone());
                                this.genome.add(chromosome);
                        }
                }
        }

        public List<Chromosome> getBugs() {
                return this.genome;
        }

        public void cicle() {
                Comparator<Chromosome> c = new Comparator<Chromosome>() {

                        public int compare(Chromosome o1, Chromosome o2) {
                                if (o1.getWeight() < o2.getWeight()) {
                                        return 1;
                                } else {
                                        return -1;
                                }
                        }
                };
                mutation();
                Collections.sort(genome, c);
                reproduction();
                Collections.sort(genome, c);
                this.purgeChromosome();
        }

        public void purgeChromosome() {
                List<Chromosome> death = new ArrayList<Chromosome>();
                for (int i = this.maxNumChromosomes; i < this.genome.size(); i++) {
                        death.add(this.genome.get(i));
                }
                for (Chromosome b : death) {
                        this.genome.remove(b);
                }
        }

        private void reproduction() {
                for (int j = 0; j < this.genome.size(); j++) {
                        Chromosome mother = this.genome.get(j);
                        if (getProbability(j)) {
                                for (int i = 0; i < this.genome.size(); i++) {
                                        if (getProbability(i)) {
                                                Chromosome father = this.genome.get(i);
                                                if (mother != father) {
                                                        int recombMotherPoint = 0;
                                                        if (mother.getNumberRemovedNodesRows() > 0) {
                                                                recombMotherPoint = this.rand.nextInt(mother.getNumberRemovedNodesRows());
                                                        }

                                                        int recombFatherPoint = 0;
                                                        if (father.getNumberRemovedNodesRows() > 0) {
                                                                recombFatherPoint = this.rand.nextInt(father.getNumberRemovedNodesRows());
                                                        }
                                                        Chromosome child = new Chromosome(mother, father, this.subNetwork.clone(), recombMotherPoint, recombFatherPoint);
                                                        genome.add(child);
                                                        i = this.genome.size();
                                                }
                                        }

                                }

                        }

                }
        }

        private void mutation() {
                for (Chromosome chromosome : this.genome) {
                        if (chromosome.getNumberDatasetNodes() > 0) {
                                int index = rand.nextInt(chromosome.getNumberDatasetNodes());
                                chromosome.mutate(index);
                        }
                }
        }

        private boolean getProbability(int i) {
                double p = (double) i / this.genome.size();
                double r = this.rand.nextDouble();
                if (r > p) {
                        return true;
                }
                return false;
        }

        public Chromosome getBestChromosome() {
                Comparator<Chromosome> c = new Comparator<Chromosome>() {

                        public int compare(Chromosome o1, Chromosome o2) {
                                if (o1.getWeight() < o2.getWeight()) {
                                        return 1;
                                } else {
                                        return -1;
                                }
                        }
                };

                Collections.sort(genome, c);
                return genome.get(0).clone();
        }

        public double getWeight() {
                Comparator<Chromosome> c = new Comparator<Chromosome>() {

                        public int compare(Chromosome o1, Chromosome o2) {
                                if (o1.getWeight() < o2.getWeight()) {
                                        return 1;
                                } else {
                                        return -1;
                                }
                        }
                };

                Collections.sort(genome, c);
                return genome.get(0).getWeight();
        }
}
